#include "hls_client.h"

#include "http_hls_connection.h"
#include "public_module/file_module/file_handle.h"

HlsClient::HlsClient(Loop * loop)
{
    m_connection           = nullptr;
    m_loop                 = loop;
    m_m3u_path             = "./";
    m_media_path           = "./";
    m_need_fetch_media_url = false;
    m_write_to_file        = true;
}

void HlsClient::MediaFilePath(const std::string & path)
{
    m_media_path = path;
}

void HlsClient::M3uFilePath(const std::string & path)
{
    m_m3u_path = path;
}

void HlsClient::Download(const std::string & url)
{
    m_url        = url;
    m_connection = std::make_shared<HttpHlsConnection>(m_loop);
    m_connection->SetOnMessageFn([this](HlsM3U8Message * message) { this->OnM3UMessage(message); });
    m_connection->SetMediaFileFn(
        [this](const std::string & url, const uint8_t * data, int length) { this->OnMediaFile(url, data, length); });
    m_connection->InitHlsUrl(m_url);
}

void HlsClient::OnM3UMessage(HlsM3U8Message * message)
{
    auto        protocol = ProtocolParser::ParserUrl(m_url);
    std::string uri      = protocol.m_uri;
    auto        pos      = uri.find_last_of('/');
    if (pos != std::string::npos)
    {
        uri = uri.substr(0, pos);
    }
    auto data = message->UriIndex();
    if (!data.empty())
    {
        for (auto & item : data)
        {
            // media file url
            if (item.m_index_uri.find("http://") != std::string::npos ||
                item.m_index_uri.find("https://") != std::string::npos)
            {
                // m_media_url.push_back(item.m_index_uri);
                printf("medai url : %s.\n", item.m_index_uri.c_str());
                m_media_url_map[item.m_index_uri].m_raw_uri = item.m_index_uri;
            }
            else
            {
                std::string url = ProtocolParser::GetUrl(protocol, uri + "/" + item.m_index_uri);
                printf("media url : %s\n", url.c_str());
                m_media_url_map[url].m_raw_uri = item.m_index_uri;
            }
        }
        if (m_write_to_file)
        {
            // write m3u8 data to file
            WriteM3U8Data(message);
            // printf("%s.\n\n", content.c_str());
        }
    }
    else if (!message->StreamInfoData().empty())
    {
        auto & stream_data = message->StreamInfoData();
        for (auto & item : stream_data)
        {
            if (item.m_stream_url.find("http://") != std::string::npos ||
                item.m_stream_url.find("https://") != std::string::npos)
            {
                printf("m3u8 url : %s.\n", item.m_stream_url.c_str());
            }
            else if (item.m_stream_url[0] == '/')
            {
                printf("m3u8 url : %s.\n", ProtocolParser::GetUrl(protocol, item.m_stream_url).c_str());
            }
            else
            {
                printf("m3u8 url : %s.\n", ProtocolParser::GetUrl(protocol, item.m_stream_url).c_str());
            }
        }
    }
    printf("media url size : %ld.\n", m_media_url_map.size());
    if (!m_media_url_map.empty())
    {
        m_connection->InitHlsUrl(m_media_url_map.begin()->first);
    }
    else
    {
    }
    if (!message->HasExtEndList())
    {
        m_need_fetch_media_url = true;
    }
}

void HlsClient::OnMediaFile(const std::string & url, const uint8_t * data, int length)
{
    printf("%s has data size : %d and url : %s%s.\n", url.c_str(), length, m_media_path.c_str(),
           m_media_url_map[url].m_raw_uri.c_str());
    if (m_write_to_file)
    {
        // write data to file
        std::string media_file = m_media_path + m_media_url_map[url].m_raw_uri;
        FileHandle  file_handle(media_file);
        if (file_handle.OpenFileReadWrite() >= 0)
        {
            file_handle.Write(data, length);
        }
        m_write_to_file = false;
    }
    m_media_url_map.erase(url);
    if (!m_media_url_map.empty())
    {
        m_connection->InitHlsUrl(m_media_url_map.begin()->first);
    }
    else
    {
        if (m_need_fetch_media_url)
        {
            m_connection->CloseConnection();
            m_connection = nullptr;
            Download(m_url);
        }
        else
        {
            m_connection->CloseConnection();
        }
    }
}

void HlsClient::WriteM3U8Data(HlsM3U8Message * message)
{
    if (!m_write_to_file)
    {
        return;
    }
    std::string content;
    HlsM3U8MessageUtil::BuildM3U8Content(message, m_media_path, content);
    printf("%s.\n\n", content.c_str());
}
